package com.hww.common.util;

import android.content.res.Resources;

import androidx.annotation.ArrayRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;

import com.hww.common.MyAppThis;

import java.nio.charset.Charset;
import java.util.IllegalFormatException;

/**
 * 提供常用的字符串操作工具方法
 */
public final class StringUtils {

    private StringUtils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }

    /**
     * 判断字符串是否为null或长度为0。
     *
     * @param s 待检查的字符串。
     * @return 如果字符串为null或长度为0则返回true，否则返回false。
     */
    public static boolean isEmpty(final CharSequence s) {
        return s == null || s.length() == 0;
    }

    /**
     * 判断给定的字符串是否为空或者仅包含空格。
     * <p>
     * 此方法通过检查字符串是否为null，或者在去除首尾空格后是否为空字符串，来确定字符串是否为空或者仅包含空格。
     * 这种检查对于处理用户输入或者从外部源获取的字符串数据非常有用，以确保数据的有效性和一致性。
     *
     * @param s 待检查的字符串
     * @return 如果字符串为空或者仅包含空格，则返回true；否则返回false。
     */
    public static boolean isTrimEmpty(final String s) {
        return (s == null || s.trim().length() == 0);
    }

    /**
     * 判断给定的字符串是否为空或者只包含空格。
     * <p>
     * 此方法主要用于检查字符串是否不包含任何有意义的字符，即字符串要么是null，要么只包含Unicode定义的空格字符。
     * 例如，制表符、换行符、以及常见的空格字符都被视为空格。
     * <p>
     * 注意，这种方法不考虑字符串的长度，即使字符串为空字符串（长度为0），也会返回true。
     *
     * @param s 待检查的字符串
     * @return 如果字符串为空、null或者只包含空格，则返回true；否则返回false。
     */
    public static boolean isSpace(final String s) {
        if (s == null) {
            return true;
        }
        for (int i = 0, len = s.length(); i < len; ++i) {
            // 遍历字符串中的每个字符，使用Character.isWhitespace方法检查字符是否为空格。
            // 如果找到任何非空格字符，则返回false，表明字符串不只包含空格
            if (!Character.isWhitespace(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }


    /**
     * 判断两个CharSequence对象是否相等。
     *
     * <p>此方法首先比较两个对象的引用是否相同，如果相同则直接判定为相等。接着检查两者是否都为非空，
     * 并且长度相等，以优化比较过程。对于字符串类型（String），它利用了String类自身的equals方法来提高效率。
     * 如果输入的对象不是字符串或长度不等，则逐字符比较字符序列的内容。</p>
     *
     * @param s1 第一个CharSequence对象用于比较。
     * @param s2 第二个CharSequence对象用于比较。
     * @return 如果两个CharSequence对象相等返回{@code true}，否则返回{@code false}。
     */
    public static boolean equals(final CharSequence s1, final CharSequence s2) {
        if (s1 == s2) {
            return true;
        }
        int length;
        if (s1 != null && s2 != null && (length = s1.length()) == s2.length()) {
            if (s1 instanceof String && s2 instanceof String) {
                return s1.equals(s2);
            } else {
                for (int i = 0; i < length; i++) {
                    if (s1.charAt(i) != s2.charAt(i)) {
                        return false;
                    }
                }
                return true;
            }
        }
        return false;
    }

    /**
     * 判断两个CharSequence是否相等，忽略大小写。
     * 该方法提供了一个重载的版本，用于比较字符串时忽略大小写。这在需要比较字符串内容而不考虑其大小写形式的场合非常有用。
     *
     * @param s1 第一个CharSequence对象，可以为null。
     * @param s2 第二个CharSequence对象，可以为null。
     * @return 如果两个CharSequence相等（忽略大小写），或者都为null，则返回true；否则返回false。
     */
    public static boolean equalsIgnoreCase(final String s1, final String s2) {
        /*equalsIgnoreCase 用于比较两个字符串是否相等，而忽略它们的大小写*/
        return s1 == null ? s2 == null : s1.equalsIgnoreCase(s2);
    }

    /**
     * 将null字符串转换为空字符串。
     * 此方法旨在处理字符串可能为null的情况，确保返回值总是一个非null的字符串。
     * 如果输入参数s为null，则返回一个空字符串；如果s不为null，则返回原字符串s。
     *
     * @param s 待处理的字符串，可能为null。
     * @return 如果输入字符串为null，则返回空字符串，否则返回原字符串。
     */
    public static String null2Length0(final String s) {
        return s == null ? "" : s;
    }

    /**
     * 计算字符序列的长度。
     *
     * @param s 要计算长度的字符序列，可以为null。
     * @return 字符序列的长度。如果字符序列为null，返回0。
     */
    public static int length(final CharSequence s) {
        return s == null ? 0 : s.length();
    }

    /**
     * 将给定字符串的第一个字母转换为大写。
     * 如果字符串为空或第一个字符已经是大写，则原样返回字符串。
     * 此方法专门处理英文字符，对于非英文字符的处理可能不适用。
     *
     * @param s 待处理的字符串。
     * @return 处理后的字符串，如果原字符串为空或第一个字符已经是大写，则返回原字符串。
     */
    public static String upperFirstLetter(final String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        /*检查第一个字符是否已经是大写*/
        if (!Character.isLowerCase(s.charAt(0))) {
            return s;
        }
        return (char) (s.charAt(0) - 32) + s.substring(1);
    }

    /**
     * 将给定字符串的首字母转换为小写。
     * 如果字符串为空或首字母已经是小写，则原样返回字符串。
     *
     * @param s 待处理的字符串
     * @return 首字母小写的字符串。如果输入为空或空字符串，则返回空字符串。
     */
    public static String lowerFirstLetter(final String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        if (!Character.isUpperCase(s.charAt(0))) {
            return s;
        }
        return String.valueOf((char) (s.charAt(0) + 32)) + s.substring(1);
    }

    /**
     * 反转给定字符串。通过将字符数组的前半部分与后半部分相互交换来实现字符串的反转
     *
     * @param s 待反转的字符串
     * @return 反转后的字符串
     */
    public static String reverse(final String s) {
        if (s == null) {
            return "";
        }
        int len = s.length();
        /*如果字符串长度小于等于1，直接返回原字符串*/
        if (len <= 1) {
            return s;
        }
        /*计算字符串的中间位置，用于指导反转操作*/
        int mid = len >> 1;
        char[] chars = s.toCharArray();
        /*使用双指针法反转字符数组*/
        char c;
        for (int i = 0; i < mid; ++i) {
            c = chars[i];
            chars[i] = chars[len - i - 1];
            chars[len - i - 1] = c;
        }
        return new String(chars);
    }

    /**
     * 将字符串从半角字符转换为全角字符。
     * 全角字符和半角字符的ASCII码值相差65248。本方法主要处理空格和ASCII码在65281-65374之间的字符。
     *
     * @param s 待转换的字符串
     * @return 转换后的字符串。如果输入为null或空字符串，则返回空字符串。
     */
    public static String toDBC(final String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        char[] chars = s.toCharArray();
        for (int i = 0, len = chars.length; i < len; i++) {
            if (chars[i] == 12288) {
                chars[i] = ' ';
            } else if (65281 <= chars[i] && chars[i] <= 65374) {
                chars[i] = (char) (chars[i] - 65248);
            } else {
                chars[i] = chars[i];
            }
        }
        return new String(chars);
    }

    /**
     * 将字符串中的半角字符转换为全角字符。
     * 全角字符和半角字符的差别在于，全角字符的宽度是半角字符的两倍。
     * 空格转换为全角空格，其他半角字符转换为对应的全角字符。
     *
     * @param s 待转换的字符串。
     * @return 转换后的字符串。如果输入为空或空字符串，则返回空字符串。
     */
    public static String toSBC(final String s) {
        if (s == null || s.length() == 0) {
            return "";
        }
        char[] chars = s.toCharArray();
        for (int i = 0, len = chars.length; i < len; i++) {
            if (chars[i] == ' ') {
                /*如果字符是空格，则转换为全角空格*/
                chars[i] = (char) 12288;
            } else if (33 <= chars[i] && chars[i] <= 126) {
                /*如果字符是半角字符（33到126之间），则转换为对应的全角字符*/
                chars[i] = (char) (chars[i] + 65248);
            } else {
                chars[i] = chars[i];
            }
        }
        return new String(chars);
    }

    /**
     * 根据资源ID获取字符串资源
     *
     * @param id 要获取的字符串资源的ID。
     * @return 格式化后的字符串，如果资源不存在，则返回资源ID的字符串表示。
     */
    public static String getString(@StringRes int id) {
        return getString(id, (Object[]) null);
    }


    /**
     * 根据资源ID获取字符串资源，并根据需要对其进行格式化。
     * <p>
     * 该方法尝试从应用程序的资源中获取指定ID的字符串资源。如果找到该资源，
     * 则使用提供的格式化参数对其进行格式化，并返回格式化后的字符串。
     * 如果未找到资源，则将资源ID转换为字符串并返回。
     *
     * @param id         要获取的字符串资源的ID。
     * @param formatArgs 用于格式化字符串的参数，可选。
     * @return 格式化后的字符串，如果资源不存在，则返回资源ID的字符串表示。
     */
    public static String getString(@StringRes int id, Object... formatArgs) {
        try {
            return format(MyAppThis.getThis().getString(id), formatArgs);
        } catch (Resources.NotFoundException e) {
            e.printStackTrace();
            return String.valueOf(id);
        }
    }

    /**
     * 根据资源ID获取字符串数组。
     * 该方法尝试从应用程序上下文中获取指定ID的字符串数组资源。如果资源不存在，
     * 则会打印异常堆栈跟踪，并返回一个包含单一元素的数组，该元素是缺失资源ID的字符串表示。
     *
     * @param id 要获取的字符串数组的资源ID。
     * @return 指定ID的字符串数组。如果资源不存在，返回包含单一元素的数组，元素为资源ID的字符串形式。
     */
    public static String[] getStringArray(@ArrayRes int id) {
        try {
            return MyAppThis.getThis().getResources().getStringArray(id);
        } catch (Resources.NotFoundException e) {
            e.printStackTrace();
            return new String[]{String.valueOf(id)};
        }
    }

    /**
     * 格式化字符串。
     *
     * @param str  要格式化的字符串，可以为null。
     * @param args 格式化参数，可以为空。
     * @return 格式化后的字符串，如果输入字符串为null，则原样返回null。
     */
    public static String format(@Nullable String str, Object... args) {
        String text = str;
        if (text != null) {
            if (args != null && args.length > 0) {
                try {
                    /*尝试根据提供的参数格式化字符串*/
                    text = String.format(str, args);
                } catch (IllegalFormatException e) {
                    e.printStackTrace();
                }
            }
        }
        return text;
    }


    /**
     * 解码字节码
     *
     * @param data    字符串
     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台
     * @return 解码后的字符串
     */
    public static String str(byte[] data, Charset charset) {
        if (data == null) {
            return null;
        }

        if (null == charset) {
            return new String(data);
        }
        return new String(data, charset);
    }

    /**
     * 解码字节码
     *
     * @param data 字符串
     * @return 解码后的字符串(默认使用 UTF - 8 解码)
     */
    public static String str(byte[] data) {
        return str(data, Charset.forName("UTF-8"));
    }


    /**
     * 编码字符串，使用UTF - 8编码
     *
     * @param str 字符串
     * @return 编码后的字节码
     */
    public static byte[] bytes(CharSequence str) {
        return bytes(str, Charset.forName("UTF-8"));
    }

    /**
     * 编码字符串
     *
     * @param str     字符串
     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台
     * @return 编码后的字节码
     */
    public static byte[] bytes(CharSequence str, Charset charset) {
        if (str == null) {
            return null;
        }

        if (null == charset) {
            return str.toString().getBytes();
        }
        return str.toString().getBytes(charset);
    }

}
